package ch.idsia.scenarios;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import ch.idsia.ai.agents.Agent;
import ch.idsia.tools.CmdLineOptions;
import ch.idsia.tools.EvaluationInfo;
import ch.idsia.tools.EvaluationOptions;
import ch.idsia.tools.Evaluator;

import competition.cig.cs478.CS478_AStar_Backprop_Learner;
import competition.cig.cs478.CS478_BackpropAgent;
import competition.cig.cs478.CS478_TweenAgent;
import competition.cig.cs478.backprop.Network;
import competition.cig.cs478.backprop.NetworkAdapter;

public class TweenLearnerRun {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		String tween_filename = "tween_network2.ser";
		String normal_filename = "normal_network2.ser";
		train_tween(tween_filename, 100);
		train(normal_filename, 100);
		evaluate(tween_filename, 100);
		evaluate(normal_filename, 100);
		

	}
	
	private static void evaluate(String filename, int iterations) {
        // Load/create network from file
		Network network = null;
		try {
			network = loadNetworkFromFile(filename);
		}
		catch(FileNotFoundException e) {
			NetworkAdapter adapter = new NetworkAdapter();
			network = new Network(adapter.getInputCount(), adapter.getInputCount() * 2, 1, adapter.getOutputCount());
		}
		catch (Exception e) {
			e.printStackTrace();
		}

		// constant level options
		EvaluationOptions options = new CmdLineOptions(new String[0]);
        options.setMaxFPS(true);
        options.setVisualization(false);
        options.setNumberOfTrials(1);
        options.setMatlabFileName("");
        options.setLevelDifficulty(1);
		Agent controller = new CS478_BackpropAgent(network);
		options.setAgent(controller);
		
		System.out.println("Iteration\tPercent Complete");
		while (iterations-- > 0) {
			int seed = (int) (Math.random () * Integer.MAX_VALUE);
			options.setLevelRandSeed(seed);
			Evaluator evaluator = new Evaluator (options);
			EvaluationInfo result = evaluator.evaluate().get(0);
			int lengthOfLevelPassedCells = result.lengthOfLevelPassedCells;
			int totalLengthOfLevelCells = result.totalLengthOfLevelCells;
			double percentComplete = (double)lengthOfLevelPassedCells / (double) totalLengthOfLevelCells;
			System.out.println(iterations + "\t" + percentComplete);
		}    		
	}
	
	private static void train_tween(String filename, int iterations) {
		// Level options
		EvaluationOptions options = new CmdLineOptions(new String[0]);
        options.setMaxFPS(true);
        options.setVisualization(false);
        options.setNumberOfTrials(1);
        options.setMatlabFileName("");
        options.setLevelDifficulty(1);
        
        // Load/create network from file
		Network network = null;
		try {
			network = loadNetworkFromFile(filename);
		}
		catch(FileNotFoundException e) {
			NetworkAdapter adapter = new NetworkAdapter();
			network = new Network(adapter.getInputCount(), adapter.getInputCount() * 2, 1, adapter.getOutputCount());
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		
		// Controller
		CS478_TweenAgent agent = new CS478_TweenAgent(network);
		agent.setBackpropPeriod(2);
		agent.setAstarPeriod(4);
		
		// Loop variables
		boolean reloadNetwork = true;
		
		while (iterations-- > 0) {
			if (reloadNetwork) {
				try {
					network = loadNetworkFromFile(filename);
					reloadNetwork = false;
				}
				catch(FileNotFoundException e) {
					NetworkAdapter adapter = new NetworkAdapter();
					network = new Network(adapter.getInputCount(), adapter.getInputCount() * 2, 1, adapter.getOutputCount());
				}
				catch(Exception e) {
					e.printStackTrace();
				}
			}
	        agent.setNetwork(network);
	        options.setAgent(agent);
	        int seed = (int) (Math.random () * Integer.MAX_VALUE);
	        options.setLevelRandSeed(seed);
	        System.out.println("Seed: " + seed);
	        Evaluator evaluator = new Evaluator (options);
            EvaluationInfo result = evaluator.evaluate().get(0);
	        if(result.marioStatus == 1) {
	        	System.out.println("Saving result from iteration " + iterations);
	        	try{
	        		saveNetworkToFile(network, filename);
	        	}
	        	catch (Exception e) {
	        		e.printStackTrace();
	        	}
	        } else {
	        	System.out.println("Disregarding result from iteration " + iterations);
	        	reloadNetwork = true;
	        }
		}		
	}
	
	private static void train(String filename, int iterations) {
		// Level options
		EvaluationOptions options = new CmdLineOptions(new String[0]);
        options.setMaxFPS(true);
        options.setVisualization(false);
        options.setNumberOfTrials(1);
        options.setMatlabFileName("");
        options.setLevelDifficulty(1);
        
        // Load/create network from file
		Network network = null;
		try {
			network = loadNetworkFromFile(filename);
		}
		catch(FileNotFoundException e) {
			NetworkAdapter adapter = new NetworkAdapter();
			network = new Network(adapter.getInputCount(), adapter.getInputCount() * 2, 1, adapter.getOutputCount());
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		
		// Controller
		CS478_AStar_Backprop_Learner agent = new CS478_AStar_Backprop_Learner(network);
		
		// Loop variables
		boolean reloadNetwork = true;
		
		while (iterations-- > 0) {
			if (reloadNetwork) {
				try {
					network = loadNetworkFromFile(filename);
					reloadNetwork = false;
				}
				catch(FileNotFoundException e) {
					NetworkAdapter adapter = new NetworkAdapter();
					network = new Network(adapter.getInputCount(), adapter.getInputCount() * 2, 1, adapter.getOutputCount());
				}
				catch(Exception e) {
					e.printStackTrace();
				}
			}
	        agent.setNetwork(network);
	        options.setAgent(agent);
	        int seed = (int) (Math.random () * Integer.MAX_VALUE);
	        options.setLevelRandSeed(seed);
	        System.out.println("Seed: " + seed);
	        Evaluator evaluator = new Evaluator (options);
            EvaluationInfo result = evaluator.evaluate().get(0);
	        if(result.marioStatus == 1) {
	        	System.out.println("Saving result from iteration " + iterations);
	        	try{
	        		saveNetworkToFile(network, filename);
	        	}
	        	catch (Exception e) {
	        		e.printStackTrace();
	        	}
	        } else {
	        	System.out.println("Disregarding result from iteration " + iterations);
	        	reloadNetwork = true;
	        }
		}		
	}	
	
	private static Network loadNetworkFromFile(String filename) throws Exception {
		FileInputStream fis = new FileInputStream(filename);
		ObjectInputStream ois = new ObjectInputStream(fis);
		Network n = (Network)ois.readObject();
		ois.close();
		return n;
	}
	
	private static void saveNetworkToFile(Network network, String filename) throws Exception {
		FileOutputStream fos = new FileOutputStream(filename);
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(network);
		oos.close();
	}
}
